﻿using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace LockCrypt.Mobile {
    public static class Utils {
        public static Random seed = new Random();
        /// <summary>
        /// Reads a stream to the end.
        /// </summary>
        /// <param name="stream">The stream to read.</param>
        /// <param name="initialLength">The initial length of the buffer to use.</param>
        /// <returns>A byte array containing the bytes read.</returns>
        public static byte[] ReadFully(Stream stream, int initialLength) {
            if(initialLength < 1)
                initialLength = 32768;
            byte[] buffer = new byte[initialLength];
            int read = 0;
            int chunk;
            while((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0) {
                read += chunk;
                if(read == buffer.Length) {
                    int nextByte = stream.ReadByte();
                    if(nextByte == -1)
                        return buffer;
                    byte[] newBuffer = new byte[buffer.Length * 2];
                    Array.Copy(buffer, newBuffer, buffer.Length);
                    newBuffer[read] = (byte)nextByte;
                    buffer = newBuffer;
                    read++;
                }
            }
            byte[] ret = new byte[read];
            Array.Copy(buffer, ret, read);
            return ret;
        }

        /// <summary>
        /// Reduces the size of the font on the specified label by 1em until the text fits inside the label's bounds.
        /// </summary>
        /// <param name="g">The graphics object to use.</param>
        /// <param name="label">The label.</param>
        public static void FitFontSizeToLabel(Graphics g, Label label) {
            bool done = false;
            while(!done) {
                if(g.MeasureString(label.Text, label.Font).Width > label.Width) {
                    if(label.Font.Size == 1)
                        return;
                    label.Font = new Font(label.Font.Name, label.Font.Size - 1, label.Font.Style);
                } else {
                    done = true;
                }
            }
        }
        /// <summary>
        /// Enlarges the label to text on the label by making it higher (width remains constant).
        /// </summary>
        /// <param name="g">The g.</param>
        /// <param name="label">The label.</param>
        /// <param name="fontHeight">Height of the font.</param>
        /// <returns></returns>
        public static int EnlargeLabelToText(Graphics g, Label label, int fontHeight) {
            return fontHeight * (int)Math.Ceiling(g.MeasureString(label.Text, label.Font).Width / label.Width);
        }
        /// <summary>
        /// Converts a UNIX time to a .NET DateTime.
        /// </summary>
        /// <param name="unixTime">The unix time.</param>
        /// <returns></returns>
        public static DateTime UNIXTimeToDateTime(double unixTime) {
            return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(unixTime).ToLocalTime();
        }

        /// <summary>
        /// Converts a .NET DateTime to UNIX time.
        /// </summary>
        /// <param name="time">The DateTime.</param>
        /// <returns></returns>
        public static double DateTimeToUNIXTime(DateTime time) {
            TimeSpan span = (time - new DateTime(1970, 1, 1).ToLocalTime());
            TimeSpan offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
            double t = span.TotalSeconds - offset.TotalSeconds;
            if(t > 1104537600) {
                return (t);
            } else {
                return 1800000000;
            }
        }

        /// <summary>
        /// A class for detecting the platform of the host device
        /// </summary>
        public class PlatformDetector {
            [DllImport("coredll.dll")]
            private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, StringBuilder pvParam, uint fWinIni);

            private static uint SPI_GETPLATFORMTYPE = 257;

            public static Platform GetPlatform() {
                Platform plat = Platform.Unknown;
                switch(System.Environment.OSVersion.Platform) {
                    case PlatformID.Win32NT:
                        plat = Platform.Win32NT;
                        break;
                    case PlatformID.Win32S:
                        plat = Platform.Win32S;
                        break;
                    case PlatformID.Win32Windows:
                        plat = Platform.Win32Windows;
                        break;
                    case PlatformID.WinCE:
                        plat = CheckWinCEPlatform();
                        break;
                }

                return plat;
            }

            static Platform CheckWinCEPlatform() {
                Platform plat = Platform.WindowsCE;
                StringBuilder strbuild = new StringBuilder(200);
                SystemParametersInfo(SPI_GETPLATFORMTYPE, 200, strbuild, 0);
                string str = strbuild.ToString();
                switch(str) {
                    case "PocketPC":
                        plat = Platform.PocketPC;
                        break;
                    case "SmartPhone":
                        // Note that the strbuild parameter from the
                        // PInvoke returns "SmartPhone" with an
                        // upper case P. The correct casing is
                        // "Smartphone" with a lower case p.
                        plat = Platform.Smartphone;
                        break;
                }
                return plat;
            }
        }

        public enum Platform {
            PocketPC, WindowsCE, Smartphone, Win32NT, Win32S, Win32Windows, Unknown
        }

    }
}
